`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/05/05 23:18:17
// Design Name: 
// Module Name: fifo
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/02/22 00:05:11
// Design Name: 
// Module Name: sync_fifo
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module sync_fifo
#(parameter DATA_WIDTH = 32,
  parameter FIFO_DEPTH = 8)
(
input logic clk,
input logic rst,
input logic wr_en,
input logic [DATA_WIDTH-1:0] wdata,
input logic rd_en,
output logic [DATA_WIDTH-1:0] rdata,
output logic full,
output logic empty
    );
logic [$clog2(FIFO_DEPTH)-1:0] wr_ptr;                  //指向下一个要写的地址
logic [$clog2(FIFO_DEPTH)-1:0] rd_ptr;                  //指向下一个要读的地址
logic [$clog2(FIFO_DEPTH):0] wr_addr;                   //最高位用来标记空满
logic [$clog2(FIFO_DEPTH):0] rd_addr;                   //最高位用来标记空满
//
assign wr_ptr=wr_addr[$clog2(FIFO_DEPTH)-1:0];
assign rd_ptr=rd_addr[$clog2(FIFO_DEPTH)-1:0];
//
logic [DATA_WIDTH-1:0] FIFO [0:FIFO_DEPTH-1];
//wr_addr
always_ff@(posedge clk,posedge rst)
if(rst)
    wr_addr<=0;                                    //复位时写指针为0
else if(wr_en&&~full)                             //写使能信号有效且fifo未满
    wr_addr<=wr_addr+1;
//rd_addr
always_ff@(posedge clk,posedge rst)
if(rst)
    rd_addr<=0;
else if(rd_en&&~empty)                            //写使能信号有效且FIFO非空
    rd_addr<=rd_addr+1;
//flag
assign full=(rd_addr=={~wr_addr[$clog2(FIFO_DEPTH)],wr_ptr})?1'b1:1'b0;
assign empty=(rd_addr==wr_addr)?1'b1:1'b0;
//write
always_ff@(posedge clk)
if(wr_en&&~full)
    FIFO[wr_ptr]<=wdata;
//read
always_ff@(posedge clk,posedge rst)          //rd_en拉高后的下一个周期读出
if(rst)
    rdata<=0;
else if(rd_en&&~empty)
    rdata<=FIFO[rd_ptr];
endmodule

